package net.xdclass.component;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import com.amazonaws.util.IOUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * MinIO 文件存储引擎实现类，基于 AWS SDK 的 AmazonS3Client 实现。
 */
@Component
@Slf4j
public class MinIOFileStoreEngine implements StoreEngine {

    private static final String CONTENT_TYPE_FORCE_DOWNLOAD = "application/force-download";

    @Resource
    private AmazonS3Client amazonS3Client;

    /**
     * 判断指定名称的 Bucket 是否存在。
     *
     * @param bucketName Bucket 名称
     * @return 是否存在
     */
    @Override
    public boolean bucketExists(String bucketName) {
        if (bucketName == null || bucketName.isEmpty()) {
            log.warn("bucket名称为空");
            return false;
        }
        return amazonS3Client.doesBucketExistV2(bucketName);
    }

    /**
     * 删除指定名称的 Bucket。
     *
     * @param bucketName Bucket 名称
     * @return 删除成功返回 true，否则返回 false
     */
    @Override
    public boolean removeBucket(String bucketName) {
        if (!bucketExists(bucketName)) {
            log.warn("尝试删除不存在的 bucket: {}", bucketName);
            return false;
        }
        try {
            amazonS3Client.deleteBucket(bucketName);
            log.info("bucket删除成功: {}", bucketName);
            return true;
        } catch (Exception e) {
            log.error("删除 bucket 失败: {}", bucketName, e);
            return false;
        }
    }

    /**
     * 创建指定名称的 Bucket。
     *
     * @param bucketName Bucket 名称
     */
    @Override
    public void createBucket(String bucketName) {
        if (bucketExists(bucketName)) {
            log.info("bucket已存在: {}", bucketName);
            return;
        }
        try {
            amazonS3Client.createBucket(bucketName);
            log.info("bucket创建成功: {}", bucketName);
        } catch (Exception e) {
            log.error("创建 bucket 失败: {}", bucketName, e);
        }
    }

    /**
     * 获取所有 Bucket。
     *
     * @return 所有 Bucket 列表
     */
    @Override
    public List<Bucket> getAllBucket(String bucketName) {
        try {
            return amazonS3Client.listBuckets();
        } catch (Exception e) {
            log.error("获取所有 bucket 失败", e);
            return List.of();
        }
    }

    /**
     * 列出指定 Bucket 中的所有对象。
     *
     * @param bucketName Bucket 名称
     * @return 对象摘要列表
     */
    @Override
    public List<S3ObjectSummary> listObjects(String bucketName) {
        if (!bucketExists(bucketName)) {
            log.warn("bucket不存在，无法列出对象: {}", bucketName);
            return List.of();
        }
        try {
            return amazonS3Client.listObjects(bucketName).getObjectSummaries();
        } catch (Exception e) {
            log.error("列出 bucket 对象失败: {}", bucketName, e);
            return List.of();
        }
    }

    /**
     * 判断指定对象是否存在于指定 Bucket 中。
     *
     * @param bucketName Bucket 名称
     * @param objectKey  对象键
     * @return 是否存在
     */
    @Override
    public boolean doesObjectExist(String bucketName, String objectKey) {
        if (!bucketExists(bucketName)) {
            log.warn("bucket不存在，无法检查对象是否存在: {}", bucketName);
            return false;
        }
        try {
            return amazonS3Client.doesObjectExist(bucketName, objectKey);
        } catch (Exception e) {
            log.error("检查对象是否存在失败: {}/{}", bucketName, objectKey, e);
            return false;
        }
    }

    /**
     * 从本地路径上传文件到指定 Bucket。
     *
     * @param bucketName     Bucket 名称
     * @param objectkey      对象键
     * @param localFileName  本地文件路径
     * @return 上传成功返回 true，否则返回 false
     */
    @Override
    public boolean upload(String bucketName, String objectkey, String localFileName) {
        if (!bucketExists(bucketName)) {
            log.warn("bucket不存在，无法上传文件: {}", bucketName);
            return false;
        }
        try {
            amazonS3Client.putObject(bucketName, objectkey, new File(localFileName));
            log.info("文件上传成功: {}/{}", bucketName, objectkey);
            return true;
        } catch (Exception e) {
            log.error("文件上传失败: {}/{}", bucketName, objectkey, e);
            return false;
        }
    }

    /**
     * 上传 MultipartFile 到指定 Bucket。
     *
     * @param bucketName Bucket 名称
     * @param objectKey  对象键
     * @param file       MultipartFile 文件
     * @return 上传成功返回 true，否则返回 false
     */
    @Override
    public boolean upload(String bucketName, String objectKey, MultipartFile file) {
        if (!bucketExists(bucketName)) {
            log.warn("bucket不存在，无法上传文件: {}", bucketName);
            return false;
        }
        if (file.isEmpty()) {
            log.warn("上传文件为空");
            return false;
        }
        try {
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentType(file.getContentType());
            objectMetadata.setContentLength(file.getSize());
            amazonS3Client.putObject(bucketName, objectKey, file.getInputStream(), objectMetadata);
            log.info("文件上传成功: {}/{}", bucketName, objectKey);
            return true;
        } catch (IOException e) {
            log.error("读取上传文件失败", e);
            return false;
        } catch (Exception e) {
            log.error("上传文件失败: {}/{}", bucketName, objectKey, e);
            return false;
        }
    }

    /**
     * 删除指定 Bucket 中的对象。
     *
     * @param bucketName Bucket 名称
     * @param objectKey  对象键
     * @return 删除成功返回 true，否则返回 false
     */
    @Override
    public boolean delete(String bucketName, String objectKey) {
        if (!bucketExists(bucketName)) {
            log.warn("bucket不存在，无法删除对象: {}", bucketName);
            return false;
        }
        try {
            amazonS3Client.deleteObject(bucketName, objectKey);
            log.info("对象删除成功: {}/{}", bucketName, objectKey);
            return true;
        } catch (Exception e) {
            log.error("删除对象失败: {}/{}", bucketName, objectKey, e);
            return false;
        }
    }



    /**
     * 将指定对象内容写入 HttpServletResponse，用于浏览器下载。
     *
     * @param bucketname Bucket 名称
     * @param objectKey  对象键
     * @param response   HTTP 响应对象
     */
    @Override
    @SneakyThrows
    public void download2Response(String bucketname, String objectKey, HttpServletResponse response) {
        if (!bucketExists(bucketname)) {
            log.warn("bucket不存在，无法下载对象: {}", bucketname);
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Bucket 不存在");
            return;
        }
        if (!doesObjectExist(bucketname, objectKey)) {
            log.warn("对象不存在，无法下载: {}/{}", bucketname, objectKey);
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "对象不存在");
            return;
        }

        try (S3Object s3Object = amazonS3Client.getObject(bucketname, objectKey)) {
            String fileName = extractFileNameFromKey(objectKey);
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
            response.setContentType(CONTENT_TYPE_FORCE_DOWNLOAD);
            response.setCharacterEncoding("UTF-8");

            IOUtils.copy(s3Object.getObjectContent(), response.getOutputStream());
        } catch (Exception e) {
            log.error("下载文件失败: {}/{}", bucketname, objectKey, e);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "下载失败");
        }
    }

    /**
     * 从对象 Key 提取文件名部分。
     *
     * @param objectKey 对象键
     * @return 文件名
     */
    private String extractFileNameFromKey(String objectKey) {
        int lastSlashIndex = objectKey.lastIndexOf('/');
        if (lastSlashIndex >= 0 && lastSlashIndex < objectKey.length() - 1) {
            return objectKey.substring(lastSlashIndex + 1);
        }
        return objectKey;
    }
}
